Composing multiple layers to make a custom plot type
What is a composite layer?
Composite layer is a layer which is constructed using two or more layers together. Once registered this can be used just like a normal layer (bar, point, etc.) is used. This allows reusability, define once use anywhere functionality with Muze.
Defining and registering a new composite layer
Layer instances are created internally by canvas using layerFactory.
layerFactory
Creates layer instances and registers composite layer definitions. Layer instances are created internally by canvas using layerFactory.
To access layerFactory:
const layerFactory = muze.layerFactory;
composeLayers
Registers composite layer definition in the layer factory:
composeLayers(layerName, definition);
// layerName - Name of the new layer
// definition - Configuration of the new layer
The definition we pass in to composeLayers is registered internally, which can then be used as a mark type in the layers configuration.
Adding the composite layer to a canvas
Below is an example using composite layers:
Example
const { muze } = viz;
const data = [
{
$SID: "discount",
account_mgr: "Andy Bernard",
region: "Midwest",
discount: 18.52,
quantity: null,
},
{
$SID: "discount",
account_mgr: "Andy Bernard",
region: "Northeast",
discount: 28.63,
quantity: null,
},
{
$SID: "discount",
account_mgr: "Andy Bernard",
region: "South",
discount: 89,
quantity: null,
},
{
$SID: "discount",
account_mgr: "Andy Bernard",
region: "West",
discount: 72.25,
quantity: null,
},
{
$SID: "discount",
account_mgr: "Angela Martin",
region: "Midwest",
discount: 29.88,
quantity: null,
},
{
$SID: "discount",
account_mgr: "Angela Martin",
region: "Northeast",
discount: 7.65,
quantity: null,
},
{
$SID: "discount",
account_mgr: "Angela Martin",
region: "South",
discount: 42.25,
quantity: null,
},
{
$SID: "discount",
account_mgr: "Angela Martin",
region: "West",
discount: 36.92,
quantity: null,
},
{
$SID: "discount",
account_mgr: "Creed Patton",
region: "Midwest",
discount: 6.96,
quantity: null,
},
{
$SID: "discount",
account_mgr: "Creed Patton",
region: "Northeast",
discount: 44.04,
quantity: null,
},
{
$SID: "discount",
account_mgr: "Creed Patton",
region: "South",
discount: 37.58,
quantity: null,
},
{
$SID: "discount",
account_mgr: "Creed Patton",
region: "West",
discount: 25.79,
quantity: null,
},
{
$SID: "quantity",
account_mgr: "Andy Bernard",
region: "Northeast",
discount: null,
quantity: 25,
},
{
$SID: "quantity",
account_mgr: "Angela Martin",
region: "Northeast",
discount: null,
quantity: 65,
},
{
$SID: "quantity",
account_mgr: "Creed Patton",
region: "Northeast",
discount: null,
quantity: 46,
},
];
const schema = [
{
name: "$SID",
type: "dimension",
subtype: "categorical",
},
{
name: "account_mgr",
type: "dimension",
subtype: "categorical",
},
{
name: "region",
type: "dimension",
subtype: "categorical",
},
{
name: "discount",
type: "measure",
subtype: "continuous",
},
{
name: "quantity",
type: "measure",
subtype: "continuous",
},
];
const formattedData = await DataModel.loadData(data, schema);
let dm = new DataModel(formattedData);
const share = muze.Operators.share;
const layerFactory = muze.layerFactory;
layerFactory.composeLayers("composedMark", [
{
mark: "bar",
encoding: {
y: "composedMark.encoding.y0_foo",
x: "composedMark.encoding.x",
color: "composedMark.encoding.color",
},
transform: {
type: "stack",
},
transition: {
disabled: true,
},
source: "composedMark.barSourceABC",
},
{
mark: "line",
encoding: {
y: "composedMark.encoding.y1_foo",
x: "composedMark.encoding.x",
},
transition: {
disabled: true,
},
source: "composedMark.lineSourceXYZ",
},
]);
muze
.canvas()
.rows([share("discount", "quantity")])
.columns(["account_mgr"])
.layers([
{
mark: "composedMark",
encoding: {
x: "account_mgr",
y0_foo: "discount",
y1_foo: "quantity",
color: "region",
},
barSourceABC: "discount",
lineSourceXYZ: "quantity",
},
])
.config({
autoGroupBy: {
disabled: true,
},
axes: {
y: {
showAxisLine: true,
},
},
})
.transform({
discount: (dataset) => {
return dataset.select({
field: "$SID",
operator: "eq",
value: "discount",
});
},
quantity: (dataset) => {
return dataset.select({
field: "$SID",
operator: "eq",
value: "quantity",
});
},
})
.data(dm)
.width(750)
.height(700)
.mount("#chart");
Let us understand the major parts of the sample above:
- composedMark will be the name of the new layer
- we set the y encoding for the bar layer to make vertical bars
- Also we add a color to the bars along with a line layer
- On the layers config, we pass the appropriate fields to the composedMark layer's encoding, which (bar and line) is then rendered on the chart